﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using FileSystem.Models;
using FileSystem.Services.IServices;
using SQLite;

namespace FileSystem.Services.Realization {
    public class DiskBlockStorage : IDiskBlockStorage {
        // ******** 公开变量
        /// <summary>
        /// DiskBlockTable文件路径
        /// </summary>
        public static readonly string DbPath = Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder
                .LocalApplicationData), DbName);

        /// <summary>
        /// DiskBlockTable数据库连接
        /// </summary>
        private SQLiteAsyncConnection _connection;

        public SQLiteAsyncConnection Connection =>
            _connection ?? (_connection = new SQLiteAsyncConnection(DbPath));

        // ******** 私有变量
        /// <summary>
        /// TableDb文件名
        /// </summary>
        private const string DbName = "DiskBlockTable.sqlite3";

        /// <summary>
        /// 偏好存储服务
        /// </summary>
        private IPreferenceStorage _preferenceStorage;

        // ******** 继承方法
        /// <summary>
        /// 初始化磁盘块存储
        /// </summary>
        public async Task InitializeAsync() {
            // DiskBlockTable.sqlite3 文件初始化
            await Connection.CreateTableAsync<DiskBlock>();

            // 将64个磁盘块信息写入物理磁盘块表中
            for (var i = 0; i < PhysicalDiskBlockConst.Count; i++) {
                var diskBlock = new DiskBlock {
                    PhysicalBlockType = (int) DiskBlockConst.Type.Null
                };

                if (i == PhysicalDiskBlockConst.Count - 1)
                    diskBlock.NextOne = -1;
                else
                    diskBlock.NextOne = i + 2;
                await Connection.InsertAsync(diskBlock);
            }

            _preferenceStorage.Set(DiskBlockStorageConstants.VersionKey,
                DiskBlockStorageConstants.Version);
        }

        /// <summary>
        /// 磁盘块存储是否已经初始化
        /// </summary>
        public bool IsInitialized() {
            return _preferenceStorage.Get(DiskBlockStorageConstants.VersionKey,
                    DiskBlockStorageConstants.DefaultVersion) ==
                DiskBlockStorageConstants.Version;
        }

        /// <summary>
        /// 增加磁盘块
        /// </summary>
        /// <param name="diskBlock">要添加的磁盘块</param>
        public async Task AddAsync(DiskBlock diskBlock) {
            await Connection.InsertAsync(diskBlock);
        }

        /// <summary>
        /// 删除磁盘块
        /// </summary>
        /// <param name="diskBlock">要删除的磁盘块</param>
        public async Task RemoveAsync(DiskBlock diskBlock) {
            await Connection.DeleteAsync(diskBlock);
        }

        /// <summary>
        /// 修改磁盘块属性
        /// </summary>
        /// <param name="diskBlock">磁盘块</param>
        /// <param name="property">属性</param>
        /// <param name="newContent">新值</param>
        /// <returns></returns>
        public async Task ModifyProperty(DiskBlock diskBlock,
            DiskBlockConst.Property property, int newContent) {
            switch (property) {
                case DiskBlockConst.Property.PhysicalBlockType: {
                    diskBlock.PhysicalBlockType = newContent;
                    await Connection.InsertOrReplaceAsync(diskBlock);
                    break;
                }
                case DiskBlockConst.Property.NextOne: {
                    diskBlock.NextOne = newContent;
                    await Connection.InsertOrReplaceAsync(diskBlock);
                    break;
                }
            }
        }

        /// <summary>
        /// 根据物理块号获得一个磁盘块
        /// </summary>
        /// <param name="physicalBlockNumber">物理块号</param>
        public async Task<DiskBlock> GetDiskBlock(int physicalBlockNumber) {
            return await Connection.Table<DiskBlock>().FirstOrDefaultAsync(p =>
                p.PhysicalBlockNumber == physicalBlockNumber);
        }

        /// <summary>
        /// 得到第一个空磁盘块
        /// </summary>
        public async Task<DiskBlock> GetFirstNullDiskBlock() {
            // return await Connection.Table<DiskBlock>().FirstOrDefaultAsync(p =>
            //     p.PhysicalBlockType == (int) DiskBlockConst.Type.Null);
            return await GetDiskBlock(DiskBlockConst.First);
        }

        /// <summary>
        /// 得到最后一个空磁盘块
        /// </summary>
        public async Task<DiskBlock> GetLastNullDiskBlock() {
            // var list = await Connection.Table<DiskBlock>().Where(p =>
            //         p.PhysicalBlockType == (int) DiskBlockConst.Type.Null)
            //     .ToListAsync();
            //
            // if (list.Count == 0)
            //     return null;
            //
            // var diskBlock = list[list.Count - 1];
            //
            // return diskBlock;

            return await GetDiskBlock(DiskBlockConst.Last);
        }

        /// <summary>
        /// 获得所有磁盘块
        /// </summary>
        public async Task<IList<DiskBlock>> GetDiskBlocks() {
            return await Connection.Table<DiskBlock>().ToListAsync();
        }

        /// <summary>
        /// 判断磁盘块是否存在
        /// </summary>
        /// <param name="physicalBlockNumber">物理块号</param>
        public async Task<bool> Exist(int physicalBlockNumber) {
            var item = await Connection.Table<DiskBlock>()
                .FirstOrDefaultAsync(p =>
                    p.PhysicalBlockNumber == physicalBlockNumber);
            if (item == null)
                return false;
            else
                return true;
        }

        /// <summary>
        /// 判断磁盘块是否为空
        /// </summary>
        /// <param name="physicalBlockNumber">物理块号</param>
        public async Task<bool> IsNull(int physicalBlockNumber) {
            var item = await Connection.Table<DiskBlock>()
                .FirstOrDefaultAsync(p =>
                    p.PhysicalBlockNumber == physicalBlockNumber);
            if (item.PhysicalBlockType == (int)DiskBlockConst.Type.Null)
                return true;
            else
                return false;
        }

        // ******** 公开方法
        /// <summary>
        /// 磁盘块存储
        /// </summary>
        public DiskBlockStorage(IPreferenceStorage preferenceStorage) {
            _preferenceStorage = preferenceStorage;
        }

        /// <summary>
        /// 关闭数据库
        /// </summary>
        public async Task CloseAsync() {
            await Connection.CloseAsync();
        }

        // ******** 私有方法
    }
}